#include <napi.h>
#include <iostream>
#include <unordered_map>
#include <string>
#include "../include/huffmanNode.h" // 假设HuffmanNode.h包含了HuffmanNode的声明和Huffman树的操作
#include "../include/huffmanTree.h" // 假设HuffmanTree.h包含了HuffmanNode的声明和Huffman树的操作
#include "../include/huffmanCodes.h" // 包含了哈夫曼编码的生成和操作的函数声明

Napi::Object generateFreqMapToObject(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();

    // 确保我们收到了一个文字
    if (!info[0].IsString()) {
        Napi::TypeError::New(env, "First argument must be an string").ThrowAsJavaScriptException();
    }
    // 获取输入的文字
    std::string text = info[0].As<Napi::String>().Utf8Value();

    // 计算每个字符的频率
    std::unordered_map<std::string, int> freqMap;
    freqMap = getfr(text);
    // 创建一个新的 JavaScript 对象来存储映射的键值对
    Napi::Object result = Napi::Object::New(env);
    // 遍历 unordered_map，并将键值对添加到 JavaScript 对象中
    for (auto& pair : freqMap) {
        result.Set(Napi::String::New(env, pair.first), Napi::Number::New(env, pair.second));
    }
    return result;
}
Napi::Object generateHuffmanCodesToObject(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();

    // 确保我们收到了一个文字
    if (!info[0].IsString()) {
        Napi::TypeError::New(env, "First argument must be an string").ThrowAsJavaScriptException();
    }
    // 获取输入的文字
    std::string text = info[0].As<Napi::String>().Utf8Value();

    // 计算每个字符的频率
    std::unordered_map<std::string, int> freqMap;
    freqMap = getfr(text);
    // 构建哈夫曼树
    HuffmanNode* root = buildHuffmanTree(freqMap);
    std::unordered_map<std::string, std::string> huffmanCode;
    generateCodes(root, "", huffmanCode);
    // 创建一个新的 JavaScript 对象来存储映射的键值对
    Napi::Object result = Napi::Object::New(env);
    // 遍历 unordered_map，并将键值对添加到 JavaScript 对象中
    for (auto& pair : huffmanCode) {
        result.Set(Napi::String::New(env, pair.first), Napi::String::New(env, pair.second));
    }
    return result;
}
std::unordered_map<std::string, int> convertObjectToFreqMap(const Napi::CallbackInfo& info, int index) {
    Napi::Env env = info.Env();
    // 获取 JavaScript 对象
    Napi::Object obj = info[index].As<Napi::Object>();

    // 创建一个 unordered_map 来存储结果
    std::unordered_map<std::string, int> freqMap;

    // 遍历 JavaScript 对象的所有属性
    Napi::Array keys = obj.GetPropertyNames();
    uint32_t length = keys.Length();
    for (uint32_t i = 0; i < length; ++i) {
        // 获取键
        Napi::String key = keys.Get(i).As<Napi::String>();
        std::string keyStr = key.Utf8Value();

        // 获取值，并转换为 int（注意：这里假设值都是可转换为 int 的）
        Napi::Value value = obj.Get(key);
        if (!value.IsNumber()) {
            Napi::TypeError::New(env, "Values in the object must be int").ThrowAsJavaScriptException();
        }
        int codeValue = value.As<Napi::Number>().Int32Value();
        // 将键值对添加到 unordered_map
        freqMap[keyStr] = codeValue;
    }

    return freqMap;
}

Napi::String encodeHuffmanCode(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    // 确保我们收到了一个字符串
    if (!info[0].IsString()) {
        Napi::TypeError::New(env, "First argument must be an string").ThrowAsJavaScriptException();
    }
    // 确保我们收到了一个对象
    if (!info[1].IsObject()) {
        Napi::TypeError::New(env, "First argument must be an object").ThrowAsJavaScriptException();
    }

    std::string text = info[0].As<Napi::String>().Utf8Value();  // 第一个参数是待编码的字符串
    std::unordered_map<std::string, int> freqMap;               // 初始化一个哈夫曼编码表
    freqMap = convertObjectToFreqMap(info, 1);                  // 第二个参数是哈夫曼编码的 JavaScript 对象，转换为 unordered_map
    HuffmanNode* root = buildHuffmanTree(freqMap);              // 构建哈夫曼树
    std::unordered_map<std::string, std::string> huffmanCode;   // 初始化哈夫曼编码表
    generateCodes(root, "", huffmanCode);                       // 调用 generateCodes() 函数，生成哈夫曼编码表
    std::string encodedText = encode(text, huffmanCode);        // 调用 encode() 函数，返回编码后的字符串
    Napi::String result = Napi::String::New(env, encodedText);  // 将编码后的字符串转换为 JavaScript 字符串
    return result;                                              // 返回编码后的字符串
}

Napi::String decodeHuffmanCode(const Napi::CallbackInfo& info) {
    Napi::Env env = info.Env();
    // 确保我们收到了一个字符串
    if (!info[0].IsString()) {
        Napi::TypeError::New(env, "First argument must be an string").ThrowAsJavaScriptException();
    }
    // 确保我们收到了一个对象
    if (!info[1].IsObject()) {
        Napi::TypeError::New(env, "First argument must be an object").ThrowAsJavaScriptException();
    }

    std::string text = info[0].As<Napi::String>().Utf8Value();  // 第一个参数是待解码的哈夫曼编码过的字符串
    std::unordered_map<std::string, int> freqMap;               // 初始化一个哈夫曼编码表
    freqMap = convertObjectToFreqMap(info, 1);                  // 第二个参数是哈夫曼编码的 JavaScript 对象，转换为 unordered_map
    HuffmanNode* root = buildHuffmanTree(freqMap);              // 构建哈夫曼树
    std::string decodedText = decode(root, text);               // 调用 decode() 函数，返回解码后的字符串
    Napi::String result = Napi::String::New(env, decodedText);  // 将编码后的字符串转换为 JavaScript 字符串
    return result;                                              // 返回编码后的字符串
}


Napi::Object Init(Napi::Env env, Napi::Object exports) {
    exports.Set(Napi::String::New(env, "encode"), Napi::Function::New(env, encodeHuffmanCode));
    exports.Set(Napi::String::New(env, "decode"), Napi::Function::New(env, decodeHuffmanCode));
    exports.Set(Napi::String::New(env, "generateFreqMap"), Napi::Function::New(env, generateFreqMapToObject));
    exports.Set(Napi::String::New(env, "generateHuffmanCodes"), Napi::Function::New(env, generateHuffmanCodesToObject));
    return exports;
}

// 将模块注册到 Node.js
NODE_API_MODULE(NODE_GYP_MODULE_NAME, Init)
